package internal

import (
	
	
)

// ByteInput typed interface around io.Reader or raw bytes
type ByteInput interface {
	// Next returns a slice containing the next n bytes from the buffer,
	// advancing the buffer as if the bytes had been returned by Read.
	Next(n int) ([]byte, error)
	// NextReturnsSafeSlice returns true if Next() returns a safe slice as opposed
	// to a slice that points to an underlying buffer possibly owned by another system.
	// When NextReturnsSafeSlice returns false, the result from Next() should be copied
	// before it is modified (i.e., it is immutable).
	NextReturnsSafeSlice() bool
	// ReadUInt32 reads uint32 with LittleEndian order
	ReadUInt32() (uint32, error)
	// ReadUInt16 reads uint16 with LittleEndian order
	ReadUInt16() (uint16, error)
	// GetReadBytes returns read bytes
	GetReadBytes() int64
	// SkipBytes skips exactly n bytes
	SkipBytes(n int) error
}

// NewByteInputFromReader creates reader wrapper
func ( io.Reader) ByteInput {
	return &ByteInputAdapter{
		r:         ,
		readBytes: 0,
	}
}

// NewByteInput creates raw bytes wrapper
func ( []byte) ByteInput {
	return &ByteBuffer{
		buf: ,
		off: 0,
	}
}

// ByteBuffer raw bytes wrapper
type ByteBuffer struct {
	buf []byte
	off int
}

// NewByteBuffer creates a new ByteBuffer.
func ( []byte) *ByteBuffer {
	return &ByteBuffer{
		buf: ,
	}
}

var _ io.Reader = (*ByteBuffer)(nil)

// Read implements io.Reader.
func ( *ByteBuffer) ( []byte) (int, error) {
	,  := .Next(len())
	if  != nil {
		return 0, 
	}
	copy(, )
	return len(), nil
}

// Next returns a slice containing the next n bytes from the reader
// If there are fewer bytes than the given n, io.ErrUnexpectedEOF will be returned
func ( *ByteBuffer) ( int) ([]byte, error) {
	 := len(.buf) - .off

	if  >  {
		return nil, io.ErrUnexpectedEOF
	}

	 := .buf[.off : .off+]
	.off += 

	return , nil
}

// NextReturnsSafeSlice returns false since ByteBuffer might hold
// an array owned by some other systems.
func ( *ByteBuffer) () bool {
	return false
}

// ReadUInt32 reads uint32 with LittleEndian order
func ( *ByteBuffer) () (uint32, error) {
	if len(.buf)-.off < 4 {
		return 0, io.ErrUnexpectedEOF
	}

	 := binary.LittleEndian.Uint32(.buf[.off:])
	.off += 4

	return , nil
}

// ReadUInt16 reads uint16 with LittleEndian order
func ( *ByteBuffer) () (uint16, error) {
	if len(.buf)-.off < 2 {
		return 0, io.ErrUnexpectedEOF
	}

	 := binary.LittleEndian.Uint16(.buf[.off:])
	.off += 2

	return , nil
}

// GetReadBytes returns read bytes
func ( *ByteBuffer) () int64 {
	return int64(.off)
}

// SkipBytes skips exactly n bytes
func ( *ByteBuffer) ( int) error {
	 := len(.buf) - .off

	if  >  {
		return io.ErrUnexpectedEOF
	}

	.off += 

	return nil
}

// Reset resets the given buffer with a new byte slice
func ( *ByteBuffer) ( []byte) {
	.buf = 
	.off = 0
}

// ByteInputAdapter reader wrapper
type ByteInputAdapter struct {
	r         io.Reader
	readBytes int
	buf       [4]byte
}

var _ io.Reader = (*ByteInputAdapter)(nil)

// Read implements io.Reader.
func ( *ByteInputAdapter) ( []byte) (int, error) {
	,  := io.ReadAtLeast(.r, , len())
	.readBytes += 

	if  != nil {
		return 0, 
	}

	return , nil
}

// Next returns a slice containing the next n bytes from the buffer,
// advancing the buffer as if the bytes had been returned by Read.
func ( *ByteInputAdapter) ( int) ([]byte, error) {
	 := make([]byte, )
	,  := .Read()

	if  != nil {
		return nil, 
	}
	return , nil
}

// NextReturnsSafeSlice returns true since ByteInputAdapter always returns a slice
// allocated with make([]byte, ...)
func ( *ByteInputAdapter) () bool {
	return true
}

// ReadUInt32 reads uint32 with LittleEndian order
func ( *ByteInputAdapter) () (uint32, error) {
	 := .buf[:4]
	,  := .Read()
	if  != nil {
		return 0, 
	}

	return binary.LittleEndian.Uint32(), nil
}

// ReadUInt16 reads uint16 with LittleEndian order
func ( *ByteInputAdapter) () (uint16, error) {
	 := .buf[:2]
	,  := .Read()
	if  != nil {
		return 0, 
	}

	return binary.LittleEndian.Uint16(), nil
}

// GetReadBytes returns read bytes
func ( *ByteInputAdapter) () int64 {
	return int64(.readBytes)
}

// SkipBytes skips exactly n bytes
func ( *ByteInputAdapter) ( int) error {
	,  := .Next()

	return 
}

// Reset resets the given buffer with a new stream
func ( *ByteInputAdapter) ( io.Reader) {
	.r = 
	.readBytes = 0
}